#include "stdafx.h"
#include "CppUnitTest.h"
#include <HSModel/WorldInfoController.h>
#include <HSModel/World.h>
#include <HSModel/WorldUpdater.h>
#include <HSModel/GameController.h>
#include <HSModel/Ground.h>
#include <HSModel/IRenderable.h>
#include <HSModel/Model3DStorage.h>
#include <HSModel/Tree.h>
#include <HSModel/SharedConstants.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace HSModelTests
  {
  TEST_CLASS(WorldInfoControllerTests)
    {
    public:
      TEST_METHOD(ControllerShouldHaveAllCellsFree)
        {
        //Arrange
        World world;        
        std::map<std::string, IRenderable*> objects = world.Renderable();
        Ground ground = (*world.GetGround());
        WorldInfoController info(ground, objects);
        
        //Act
        size_t counter = 0;
        for(size_t i = 0; i < GroundConstants::CELL_COUNT; ++i)
          for(size_t j = 0; j < GroundConstants::CELL_COUNT; ++j)
            if(!info.IsCellFree(TCell(i, j)))
              counter++;

        //Assert
        const size_t expected = 0;
        Assert::AreEqual(expected, counter);
        }

      TEST_METHOD(SetsWorldEntitiesProperly)
        {
        //Arrange
        World world;        
        std::map<std::string, IRenderable*> objects = world.Renderable();
        Ground ground = (*world.GetGround());

        ground.CreateWalkway(TVector2(0, 0));
        ground.CreateWalkway(TVector2(10, 10));
        std::shared_ptr<Tree> tree(new Tree(world, TT_DEFAULT_TREE));

        auto obj = tree.get();
        objects[obj->GetName()] = obj;

        // Act
        WorldInfoController info(ground, objects);

        //Assert
        EWorldEntityTypes cell_type;
        info.GetEntityOnCell(cell_type, TCell(0, 1));
        Assert::AreEqual((int)WE_GRASS, (int)cell_type);
        info.GetEntityOnCell(cell_type, TCell(1, 1));
        Assert::AreEqual((int)WE_WALKWAY, (int)cell_type);
        info.GetEntityOnCell(cell_type, TCell(0, 0));
        Assert::AreEqual((int)WE_TREE, (int)cell_type);
        }

      TEST_METHOD(FerrisWheelShouldBePlacedOn3x3Rectangle)
        {
        using namespace GroundConstants;
        TVector3 pos = TVector3(5 * CELL_SIZE + CELL_SIZE / 2, 10 * CELL_SIZE + CELL_SIZE / 2, 0);

        World world;
        world.AddFerrisWheel(pos);

        EWorldEntityTypes cell_type;
        WorldInfoController info = WorldInfoController(*world.GetGround(), world.Renderable());

        info.GetEntityOnCell(cell_type, TCell(5, 10));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(5, 9));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(4, 9));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(4, 10));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(4, 11));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);
        
        info.GetEntityOnCell(cell_type, TCell(5, 11));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(6, 11));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(6, 10));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);

        info.GetEntityOnCell(cell_type, TCell(6, 9));
        Assert::AreEqual((int)EWorldEntityTypes::WE_FERRIS, (int)cell_type);
        }

      TEST_METHOD(HumanNearShopCanAcquireBalloon)
        {
        HeightMap hm(4, 4);
        World world(hm);        
        std::map<std::string, IRenderable*> objects = world.Renderable();
        Ground ground = (*world.GetGround());

        std::shared_ptr<BalloonsShop> shop(new BalloonsShop(world));
        shop->SetPosition(TVector3(25, 25, 0)); // cell: 2, 2

        auto obj = shop.get();
        objects[obj->GetName()] = obj;
        WorldInfoController info(ground, objects);
        
        Assert::IsFalse(info.CanHumanAcquireBalloon(TVector3(30, 30, 0))); // cell : 3, 3
        Assert::IsTrue(info.CanHumanAcquireBalloon(TVector3(10, 20, 0))); // cell : 1, 2
        Assert::IsTrue(info.CanHumanAcquireBalloon(TVector3(20, 10, 0))); // cell : 2, 1
        Assert::IsTrue(info.CanHumanAcquireBalloon(TVector3(20, 30, 0))); // cell : 2, 3
        Assert::IsTrue(info.CanHumanAcquireBalloon(TVector3(30, 20, 0))); // cell : 3, 2
        }

      TEST_METHOD(ShouldBeGrassOnCellAfterRemovingBalloonsShop)
        {
        HeightMap hm(4, 4);
        World world(hm);
        GameController gcontrol;
        WorldUpdater updater(world, gcontrol);
        EWorldEntityTypes entity;

        world.AddBalloonsShop(TVector3(0, 0, 0));
        world.GenerateChangeEvent();
        
        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(0, 0)));
        Assert::AreEqual((int)WE_BALLOONS_SHOP, (int)entity);

        updater.DestroyObject(TVector2(0, 0));

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(0, 0)));
        Assert::AreEqual((int)WE_GRASS, (int)entity);
        }

      TEST_METHOD(ShouldBeGrassOnCellsAfterRemovingFerrisWheel)
        {
        HeightMap hm(10, 10);
        World world(hm);
        GameController gcontrol;
        WorldUpdater updater(world, gcontrol);
        EWorldEntityTypes entity;

        world.AddFerrisWheel(TVector3(5 * GroundConstants::CELL_SIZE, 5 * GroundConstants::CELL_SIZE, 0));
        world.GenerateChangeEvent();

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(5, 5)));
        Assert::AreEqual((int)WE_FERRIS, (int)entity);

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(4, 4)));
        Assert::AreEqual((int)WE_FERRIS, (int)entity);

        updater.DestroyObject(TVector2(5 * GroundConstants::CELL_SIZE, 5 * GroundConstants::CELL_SIZE));

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(5, 5)));
        Assert::AreEqual((int)WE_GRASS, (int)entity);

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(4, 4)));
        Assert::AreEqual((int)WE_GRASS, (int)entity);

        Assert::IsTrue(world.GetWorldInfoController()->GetEntityOnCell(entity, TCell(6, 6)));
        Assert::AreEqual((int)WE_GRASS, (int)entity);
        }
    };
  }